home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvidvi / dvidvi.c < prev    next >
C/C++ Source or Header  |  1992-06-30  |  33KB  |  1,199 lines

  1. /*
  2.  *   This program converts dvi files to dvi files;
  3.  *   the command line options are:
  4.  *
  5.  *      page n is first page selected         -f n
  6.  *      page n is last page selected          -l n
  7.  *      print at most n pages                 -n n
  8.  *      include pages (ranges allowed)        -i { n1..n2 | n1 }[,...]
  9.  *      exclude pages (ranges allowed)        -x { n1..n2 | n1 }[,...]
  10.  *      work in quiet mode                    -q
  11.  *      reverse pages                         -r
  12.  *      select even                           -m 2:1
  13.  *      select odd                            -m 2:0
  14.  *      print both on same page               -m 2:0,1(5.5in,0in)
  15.  *      do folded brochures                   -m 4:-3,0(5.5in,0in)
  16.  *                                            -m 4:1,-2(5.5in,0in)
  17.  *      etc.
  18.  *
  19.  *    The original program is by Tomas Rokicki (version 0.5) but it was
  20.  *    modified and improved by Esteban ZIMANYI ezimanyi@rc1.vub.ac.be
  21.  *    to give version 1.0.
  22.  *
  23.  *    This version has been tested for the IBM PC and compatibles under
  24.  *    compilers Turbo C 2.0 and Microsoft C 6.0.
  25.  *
  26.  */
  27. #define SEEK_SET 0
  28. #define SEEK_CUR 1
  29. #define SEEK_END 2
  30.  
  31. #define BANNER "\nThis is dvidvi 1.0, Copyright (C) 1988-91, Radical Eye Software\n"
  32. #define STRINGSIZE (500)  /* maximum number of strings in program */
  33.  
  34. #ifndef VMS
  35. #include <stdio.h>
  36. #include <string.h>
  37. #else /* VMS */
  38. #include "sys$library:stdio.h"       /* AKT: added sys$library: */
  39. #include <alloc.h>
  40. #endif /* VMS */
  41. #define MAXPPERP (32)
  42.  
  43. /* defines READBIN, WRITEBIN, PATHSEP and DIRSEP*/
  44.  
  45. #ifdef MSDOS
  46. #define READBIN         "rb"    /* MSDOS must use binary mode */
  47. #define WRITEBIN        "wb"
  48. #define PATHSEP         ';'
  49. #define DIRSEP          '\\'
  50. #else
  51. #ifdef VMS
  52. #define READBIN         "rb"    /* VMS must use binary mode */
  53. #define WRITEBIN        "wb"
  54. #define PATHSEP         ','
  55. #define DIRSEP          ':'
  56. #else
  57. #define READBIN         "r"     /* UNIX doesn't care */
  58. #define WRITEBIN        "w"
  59. #define PATHSEP         ':'
  60. #define DIRSEP          '/'
  61. #endif
  62. #endif
  63.  
  64. #ifdef XENIX
  65. #define SHORTINT
  66. #else
  67. #undef SHORTINT
  68. #endif
  69. #ifdef MSDOS
  70. #define SHORTINT
  71. #endif
  72.  
  73. /*
  74.  *   Type declarations.  integer must be a 32-bit signed; shalfword must
  75.  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
  76.  *   quarterword must be an eight-bit unsigned.
  77.  */
  78. typedef long integer;
  79. typedef char boolean;
  80. typedef short shalfword ;
  81. typedef unsigned short halfword ;
  82. typedef unsigned char quarterword ;
  83. typedef short Boolean ;
  84.  
  85. /*
  86.  *   Some globals to keep everyone happy.
  87.  */
  88. integer numpages ;      /* the total number of pages in the dvi file. */
  89. integer TeXfonts[256] ; /* information about each font */
  90. char fontseen[256] ; /* have we defined this font yet? */
  91. int modulo ;         /* our mod value */
  92. struct pagespec {
  93.    int pageno, reversed ;
  94.    long hoffset, voffset ; /* in scaled points */
  95. } pages[MAXPPERP] ;  /* the organization of the pages on output */
  96. int pagesperpage ;   /* how many pages crammed onto each page? */
  97. FILE *infile ;       /* input dvi file (cannot be a stream) */
  98. FILE *outfile ;      /* output dvi file */
  99.  
  100. char *temp ;    /* a temporary place to put things */
  101. char *nextstring, *maxstring ;
  102. char *oname ;                 /* output dvi file name */
  103. char *iname ;                 /* input dvi file name */
  104. char *strings ;               /* pointer of the string pool */
  105.  
  106. char banner[] = BANNER ;      /* the startup message */
  107. integer inlength ;      /* the length of the input dvi file */
  108. integer postloc ;       /* location of the postamble */
  109. integer mag ;           /* magnification factor */
  110. integer pagecount ;     /* number of actual pages */
  111. integer landscape = 0;     /* if landscape special, here it is! */
  112. int rem0special ;       /* should we remove the first first-page special? */
  113. integer prevpp = -1 ;      /* previous page pointer on output */
  114. integer outputpages ;   /* number of pages output */
  115. integer dviloc ;        /* our position in the output file */
  116. integer pagefake ;      /* number of pages, rounded up to multiple of modulo */
  117.  
  118. Boolean firsttransf = 0, lasttransf = 0;
  119. integer firstpage ;     /* first page selected (option -p) */
  120. integer lastpage ;      /* last page selected (option -l) */
  121. integer maxpages ;      /* maximum number of page selected (option -n) */
  122. short quiet ;             /* quiet mode (option -q) */
  123. Boolean exctransf[40][2] ; /* if the ranges of pages to exclude (option -x)
  124.                 have to be transformed */
  125. integer exclude[40][2] ; /* the ranges of pages to exclude (option -x)
  126.                          It is supposed that there are at most 40 ranges
  127.                          to exclude in the command line */
  128. short excludeseq ;       /* number of ranges to exclude (option -x) */
  129. Boolean inctransf[40][2] ; /* if the ranges of pages to exclude (option -x)
  130.                 have to be transformed */
  131. integer include[40][2] ; /* the ranges of pages to include (option -i)
  132.                          It is supposed that there are at most 40 ranges
  133.              to include in the command line */
  134. short includeseq ;       /* number of ranges to include (option -i) */
  135. integer *pageloc ;
  136. integer *pagenumbers ;
  137. int prettycolumn ;       /* the column we are at when running pretty */
  138.  
  139. /*
  140.  *   This array holds values that indicate the length of a command, if
  141.  *   we aren't concerned with that command (which is most of them) or
  142.  *   zero, if it is a special case.  This makes running through the
  143.  *   dvi file a lot easier (and probably faster) than any form of
  144.  *   dispatch table, especially since we really don't care what the
  145.  *   pages are made of.
  146.  */
  147. short comlen[256] = {
  148.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0-15 */
  149.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 16-31 */
  150.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32-47 */
  151.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 48-63 */
  152.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
  153.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80-95 */
  154.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
  155.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 112-127 */
  156.    2, 3, 4, 5, 9, 2, 3, 4, 5, 9, 1, 0, 0, 1, 1, 2, /* 128-143 */
  157.    3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, /* 144-159 */
  158.    5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, /* 160-175 */
  159.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176-191 */
  160.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-207 */
  161.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208-223 */
  162.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, /* 224-239 */
  163.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };/* 240-255 */
  164.  
  165. /*
  166.  *   Input bytes from the dvi file.
  167.  *   These routines could probably be sped up significantly; but they are
  168.  *   very machine dependent, so I will leave such tuning to the installer.
  169.  *   They simply get and return bytes in batches of one, two, three, and four,
  170.  *   updating the current position as necessary.
  171.  */
  172.  
  173. void
  174. abortpage()
  175. {
  176.    error("! unexpected eof on DVI file") ;
  177. }
  178.  
  179. shalfword dvibyte()
  180. {
  181.   register shalfword i ;
  182.   if ((i=getc(infile))==EOF)
  183.     abortpage() ;
  184.   return(i) ;
  185. }
  186.  
  187. halfword  twobytes()
  188. {
  189.   register halfword i ;
  190.   i = dvibyte() ;
  191.   return(i*256+dvibyte()) ; }
  192.  
  193. integer   threebytes()
  194. {
  195.   register integer i ;
  196.   i = twobytes() ;
  197.   return(i*256+dvibyte()) ; }
  198.  
  199. shalfword
  200. signedbyte()
  201. {
  202.   register shalfword i ;
  203.   if ((i=getc(infile))==EOF)
  204.     abortpage() ;
  205.   if (i<128) return(i) ;
  206.   else return(i-256) ;
  207. }
  208.  
  209. shalfword
  210. signedpair()
  211. {
  212.   register shalfword i ;
  213.   i = signedbyte() ;
  214.   return(i*256+dvibyte()) ;
  215. }
  216.  
  217. integer
  218. signedtrio()
  219. {
  220.   register integer i ;
  221.   i = signedpair() ;
  222.   return(i*256+dvibyte()) ;
  223. }
  224.  
  225. integer
  226. signedquad()
  227. {
  228.   register integer i ;
  229.   i = signedpair() ;
  230.   return(i*65536+twobytes()) ;
  231. }
  232.  
  233. /*
  234.  * Routines for the transformation of the pages specified with
  235.  * the @ parameter into the actual number of page from the file
  236.  *
  237.  * trans(p,q) looks for the q'th occurrence of the page numbered p
  238.  * transformpages makes the transformation for the options -f -i -l -x
  239.  */
  240.  
  241. integer transf(p,q)
  242. integer p;
  243. halfword q;
  244. {
  245. int i=0, j=0;
  246.  
  247.    while( j != q && i < pagecount )
  248.       if ( pagenumbers[i++] == p ) j++;
  249.    if ( j != q ) error ("! Page specified not found");
  250.    return (i++);
  251. }
  252. void transformpages()
  253. {
  254. int i;
  255.  
  256.    if (firsttransf) firstpage=transf(firstpage,firsttransf);
  257.    if (lasttransf) lastpage=transf(lastpage,lasttransf);
  258.    for ( i= 0; i< 40; i++) {
  259.       if (exctransf[i][0]) exclude[i][0]=transf(exclude[i][0],exctransf[i][0]);
  260.       if (exctransf[i][1]) exclude[i][1]=transf(exclude[i][1],exctransf[i][1]);
  261.       if (inctransf[i][0]) include[i][0]=transf(include[i][0],inctransf[i][0]);
  262.       if (inctransf[i][1]) include[i][1]=transf(include[i][1],inctransf[i][1]);
  263.       }
  264. }
  265. /*
  266.  *
  267.  */
  268. integer fontdeflen(p)
  269. integer p;
  270. {
  271.    fseek(infile,p+14,SEEK_SET);
  272.    return (16L+dvibyte()+dvibyte());
  273. }
  274.  
  275. /*
  276.  *       Simulation of dvibuf, get the character located at the position
  277.  *       p in the input dvi file
  278.  */
  279. unsigned char dvibuf(p)
  280. integer p;
  281. {
  282.   fseek(infile,p,SEEK_SET);
  283.   return(dvibyte());
  284. }
  285.  
  286. /*
  287.  *       Read a string of length n from the file into the string temp
  288.  */
  289. void stringdvibuf(p,n)
  290. integer p,n;
  291. {
  292.   fseek(infile,p,SEEK_SET);
  293.   while ( n-- > 0 )
  294.     *temp++ = dvibyte();
  295. }
  296.  
  297. /*
  298.  *   Print a usage error messsage, and quit.
  299.  */
  300. usage() {
  301.    (void)fprintf(stderr,banner);
  302.    (void)fprintf(stderr,"Usage:  dvidvi [options] input[.dvi] [output]\n");
  303.    (void)fprintf(stderr,"where options are:\n");
  304.    (void)fprintf(stderr,"    [-f n] first page printed     [-l n] last page printed\n");
  305.    (void)fprintf(stderr,"    [-n n] print at most n pages  \n");
  306.    (void)fprintf(stderr,"    [-i {n1..n2 | n3}[,...]] include pages\n");
  307.    (void)fprintf(stderr,"    [-x {n1..n2 | n3}[,...]] exclude pages\n");
  308.    (void)fprintf(stderr,"    [-q] quiet mode               [-r] reverse pages\n");
  309.    (void)fprintf(stderr,"    [-m modulo:pagespecs]\n");
  310. #ifndef VMS
  311.    exit(1) ;
  312. #else /* VMS */
  313.    exit(0x10000002) ;
  314.    /* AKT: was exit(1) */
  315. #endif /* VMS */
  316. }
  317. /*
  318.  *   Print an error message, and exit if it is fatal.
  319.  */
  320. error(s)
  321. char *s ;
  322. {
  323.    (void)fprintf(stderr, "%s\n", s) ;    /* AKT: was dvidvi: %s */
  324.    if (*s == '!')
  325. #ifndef VMS
  326.       exit(1) ;
  327. #else /* VMS */
  328.       exit(0x10000002) ;
  329.       /* AKT: was exit(1) */
  330. #endif /* VMS */
  331. }
  332. /*
  333.  *   This function calculates approximately (whole + num/den) * sf.
  334.  *   No need for real extreme accuracy; one ten thousandth of an
  335.  *   inch should be sufficient.
  336.  *
  337.  *   No `sf' parameter means to use an old one; inches are assumed
  338.  *   originally.
  339.  *
  340.  *   Assumptions:
  341.  *
  342.  *      0 <= num < den <= 10000
  343.  *      0 <= whole
  344.  */
  345. integer defaultscale = 4736286 ;
  346. integer scale(whole, num, den, sf)
  347. integer whole, num, den, sf ;
  348. {
  349.    integer v ;
  350.  
  351.    if (sf)
  352.       defaultscale = sf ;
  353.    else
  354.       sf = defaultscale ;
  355.    v = whole * sf + num * (sf / den) ;
  356.    if (v / sf != whole || v < 0 || v > 0x40000000L)
  357.       error("! arithmetic overflow in parameter") ;
  358.    sf = sf % den ;
  359.    v += (sf * num * 2 + den) / (2 * den) ;
  360.    return(v) ;
  361. }
  362. /*
  363.  *   Multiplies *p by 1000 and divides it by mag.  Avoiding overflow.
  364.  *
  365.  *   1 <= mag <= 1000000 ;
  366.  *   0 <= *p <= 2^30
  367.  *
  368.  *   (Could blow up if a parameter * mag / 1000 > 2^30 sp.)
  369.  */
  370. scalemag(p)
  371. long *p ;
  372. {
  373.    int negative ;
  374.  
  375.    negative = 0 ;
  376.    if (*p < 0) {
  377.       negative = 1 ;
  378.       *p = - *p ;
  379.    }
  380.    *p = 1000 * (*p / mag) + (2000 * (*p % mag) + mag) / (2 * mag) ;
  381.    if (negative)
  382.       *p = - *p ;
  383. }
  384. /*
  385.  *   Convert a sequence of digits into an integer; return -1 if no digits.
  386.  *   Advance the passed pointer as well.
  387.  */
  388. integer myatol(s)
  389. char **s ;
  390. {
  391.    register char *p ;
  392.    register integer result ;
  393.  
  394.    result = 0 ;
  395.    p = *s ;
  396.    while ('0' <= *p && *p <= '9') {
  397.       if (result > 100000000)
  398.          error("! arithmetic overflow in parameter") ;
  399.       result = 10 * result + *p++ - '0' ;
  400.    }
  401.    if (p == *s)
  402.       usage() ;
  403.    else {
  404.       *s = p ;
  405.       return(result) ;
  406.    }
  407. }
  408. /*
  409.  *   Get a dimension, allowing all the various extensions, and
  410.  *   defaults.
  411.  */
  412. integer myatodim(s)
  413. char **s ;
  414. {
  415.    register integer w, num, den ;
  416.    register char *p ;
  417.    int negative = 0 ;
  418.  
  419.    p = *s ;
  420.    if (**s == '-') {
  421.       (*s)++ ;
  422.       negative = 1 ;
  423.    }
  424.    w = myatol(s) ;
  425.    if (w < 0)
  426.       usage() ;
  427.    p = *s ;
  428.    num = 0 ;
  429.    den = 1 ;
  430.    if (*p == '.') {
  431.       p++ ;
  432.       while ('0' <= *p && *p <= '9') {
  433.          if (den < 1000) {
  434.             den *= 10 ;
  435.             num = num * 10 + *p - '0' ;
  436.          }
  437.          p++ ;
  438.       }
  439.    }
  440. /*
  441.  *   Allowed units are `in', `cm', `mm', `pt', `sp', `cc', `dd', and `pc';
  442.  *   must be in lower case.
  443.  */
  444.    if (*p == 'c' && p[1] == 'm') {
  445. /*  centimeters need to be multiplied by 72.27 * 2^16 / 2.54, or 1 864 680 */
  446.       w = scale(w, num, den, 1864680L) ;
  447.    } else if (*p == 'p' && p[1] == 't') {
  448. /*  real points need to be multiplied by 2^16 */
  449.       w = scale(w, num, den, 65536L) ;
  450.    } else if (*p == 'p' && p[1] == 'c') {
  451. /*  picas need to be multiplied by 65536 * 12, or 786 432 */
  452.       w = scale(w, num, den, 786432L) ;
  453.    } else if (*p == 'm' && p[1] == 'm') {
  454. /*  millimeters need to be multiplied by 72.27 * 2^16 / 25.4, or 186 468 */
  455.       w = scale(w, num, den, 186468L) ;
  456.    } else if (*p == 's' && p[1] == 'p') {
  457. /*  scaled points are already taken care of; simply round */
  458.       w = scale(w, num, den, 1L) ;
  459.    } else if (*p == 'b' && p[1] == 'p') {
  460. /*  big points need to be multiplied by 72.27 * 65536 / 72, or 65782 */
  461.       w = scale(w, num, den, 65782L) ;
  462.    } else if (*p == 'd' && p[1] == 'd') {
  463. /*  didot points need to be multiplied by 65536 * 1238 / 1157, or 70124 */
  464.       w = scale(w, num, den, 70124L) ;
  465.    } else if (*p == 'c' && p[1] == 'c') {
  466. /*  cicero need to be multiplied by 65536 * 1238 / 1157 * 12, or 841 489 */
  467.       w = scale(w, num, den, 841489L) ;
  468.    } else if (*p == 'i' && p[1] == 'n') {
  469. /*  inches need to be multiplied by 72.27 * 65536, or 4 736 286 */
  470.       w = scale(w, num, den, 4736286L) ;
  471.    } else {
  472. /*  use default values */
  473.       w = scale(w, num, den, 0L) ;
  474.       p -= 2 ;
  475.    }
  476.    p += 2 ;
  477.    *s = p ;
  478.    return(negative?-w:w) ;
  479. }
  480. /*
  481.  * This function determine if the page has to be printed
  482.  * depending on the values of options -f, -l, -i and -x
  483.  */
  484.  
  485. short selectedpage (n)
  486. integer n;
  487. {
  488. short i;
  489.  
  490.    if ( firstpage > n || n > lastpage ) return(0);
  491.    for ( i=0 ; i < excludeseq ; i++ )
  492.       if ( exclude[i][0] <= n && n <= exclude[i][1] )
  493.      return(0);
  494.    if (includeseq == 0) return (1);
  495.    for ( i=0 ; i < includeseq ; i++ )
  496.       if ( include[i][0] <= n && n <= include[i][1] )
  497.      return(1);
  498.    return(0);
  499. }
  500.  
  501. /*
  502.  *   Initialize sets up all the globals and data structures.
  503.  */
  504. void
  505. initialize()
  506. {
  507. int i;
  508. /* initialize values in case of option -m is not specified */
  509.    modulo = 1 ;
  510.    pages[0].hoffset = 0 ;
  511.    pages[0].voffset = 0 ;
  512.    pages[0].pageno = 0 ;
  513.    pages[0].reversed = 0 ;
  514.    pagesperpage = 1 ;
  515.    for ( i= 0; i< 40; i++) {
  516.     exctransf[i][0] = exctransf[i][1] = 0;
  517.     inctransf[i][0] = inctransf[i][1] = 0;
  518.     }
  519.    firsttransf = lasttransf = 0;
  520.  
  521.    excludeseq = 0;
  522.    includeseq = 0;
  523.    firstpage = 1;
  524.    lastpage = 1000000;
  525.    maxpages = 1000000;
  526.    quiet = 0;
  527.    strings =(char *) malloc(STRINGSIZE) ;
  528.    if (strings == 0)
  529.       error("! no memory for strings") ;
  530.    maxpages = 100000 ;
  531.    nextstring = strings ;
  532.    iname = strings ;
  533.    *nextstring++ = 0 ;
  534.     maxstring = strings + STRINGSIZE - 200;
  535. }
  536.  
  537. /*
  538.  *   Parse the arguments to the routine, and stuff everything away
  539.  *   into those globals above.
  540.  */
  541. processargs(argc, argv)
  542. int argc ;
  543. char *argv[] ;
  544. {
  545.    char *p, *q ;
  546.    int i, pageno, lastext = -1 ;
  547.    long hoffset, voffset ;
  548.    int reversed ;
  549.  
  550.    initialize ();
  551.    if (argc < 2 || argc > 8)
  552.       usage() ;
  553.  
  554. /*
  555.  *   This next whole big section of code is straightforward; we just scan
  556.  *   the options.  An argument can either immediately follow its option letter
  557.  *   or be separated by spaces.  Any argument not preceded by '-' and an
  558.  *   option letter is considered a file name.
  559.  */
  560.    for (i=1; i<argc; i++) {
  561.       if (*argv[i]=='-') {
  562.          char *p=argv[i]+2 ;
  563.          char c=argv[i][1] ;
  564.          switch (c) {
  565. case 'f' :
  566.             if (*p == 0 && argv[i+1])
  567.                p = argv[++i] ;
  568.         if (*p == '(' && *(p+1) == '@' ) {
  569.            p+=2; firsttransf = myatol(&p); p++;
  570.            }
  571.         else if (*p == '@') {
  572.            p++; firsttransf = 1 ;
  573.            }
  574. #ifdef SHORTINT
  575.             if(sscanf(p, "%d", &firstpage)==0)
  576. #else   /* ~SHORTINT */
  577.             if(sscanf(p, "%ld", &firstpage)==0)
  578. #endif  /* ~SHORTINT */
  579.            error("! Bad first page option (-f).") ;
  580.             break ;
  581. case 'i' :
  582.             if (*p == 0 && argv[i+1])
  583.                p = argv[++i] ;
  584.             while (*p != 0) {
  585.            if (*p == '(' && *(p+1) == '@' ) {
  586.           p+=2; inctransf[includeseq][0] = myatol(&p); p++;
  587.           }
  588.            else if (*p == '@') {
  589.           p++; inctransf[includeseq][0] = 1 ;
  590.           }
  591.            include[includeseq][0]=myatol(&p);
  592.                if (*p == '.' && *(p+1) == '.' ) {
  593.                   p += 2;
  594.           if (*p == '(' && *(p+1) == '@' ) {
  595.              p+=2; inctransf[includeseq][1] = myatol(&p); p++;
  596.              }
  597.           else if (*p == '@') {
  598.              p++; inctransf[includeseq][1] = 1 ;
  599.              }
  600.           include[includeseq][1] = myatol(&p);
  601.                }
  602.            else {
  603.           include[includeseq][1] = include[includeseq][0];
  604.           inctransf[includeseq][0] = inctransf[includeseq][1] ;
  605.           }
  606.            includeseq++ ;
  607.                if (*p != ',' && *p !=0 )
  608.           error("! Bad page range option (-i).") ;
  609.                if (*p == ',' )
  610.                     p++ ;
  611.             } /* while */
  612.             break ;
  613. case 'l':
  614.             if (*p == 0 && argv[i+1])
  615.                p = argv[++i] ;
  616.         if (*p == '(' && *(p+1) == '@' ) {
  617.            p+=2; lasttransf = myatol(&p); p++;
  618.            }
  619.         else if (*p == '@') {
  620.            p++; lasttransf = 1 ;
  621.            }
  622. #ifdef SHORTINT
  623.             if(sscanf(p, "%ld", &lastpage)==0)
  624. #else   /* ~SHORTINT */
  625.             if(sscanf(p, "%d", &lastpage)==0)
  626. #endif  /* ~SHORTINT */
  627.                error("! Bad last page option (-l).") ;
  628.             break ;
  629. case 'm' :
  630.             if (*p == 0 && argv[i+1])
  631.                p = argv[++i] ;
  632. /*
  633.  *   Is there a modulo supplied?  Grab it if so; otherwise default to 1.
  634.  */
  635.            for (q=p; *q != 0; q++)
  636.               if (*q == ':')
  637.                  break ;
  638.            if (*q == ':') {
  639.               modulo = myatol(&p) ;
  640.               if (*p != ':')
  641.                  usage() ;
  642.               if (modulo < 1 || modulo > MAXPPERP)
  643.                  error("! modulo must lie between 1 and 32") ;
  644.               p++ ;
  645.            }
  646. /*
  647.  *   This loop grabs all of the page specifications.
  648.  */
  649.            pagesperpage = 0 ;
  650.            while (*p != 0) {
  651.               if (pagesperpage >= MAXPPERP)
  652.                  error("! too many page specifications") ;
  653.               if (*p == '-') {
  654.                  reversed = 1 ;
  655.                  p++ ;
  656.               } else
  657.                  reversed = 0 ;
  658.               if (*p == 0 || *p == '(' || *p == ',')
  659.                  pageno = 0 ;
  660.               else
  661.                  pageno = myatol(&p) ;
  662.               if (*p == '(') {
  663.                  p++ ;
  664.                  hoffset = myatodim(&p) ;
  665.                  if (*p++ != ',')
  666.                     usage() ;
  667.                  voffset = myatodim(&p) ;
  668.                  if (*p++ != ')')
  669.                     usage() ;
  670.               } else {
  671.                  hoffset = 0 ;
  672.                  voffset = 0 ;
  673.               }
  674.               pages[pagesperpage].hoffset = hoffset ;
  675.               pages[pagesperpage].voffset = voffset ;
  676.               pages[pagesperpage].pageno = pageno ;
  677.               pages[pagesperpage].reversed = reversed ;
  678.               pagesperpage++ ;
  679.               if (*p == ',')
  680.                  p++ ;
  681.            } /* while */
  682.            break ;
  683. case 'n' :
  684.             if (*p == 0 && argv[i+1])
  685.                p = argv[++i] ;
  686. #ifdef SHORTINT
  687.             if (sscanf(p, "%ld", &maxpages)==0)
  688. #else   /* ~SHORTINT */
  689.             if (sscanf(p, "%d", &maxpages)==0)
  690. #endif  /* ~SHORTINT */
  691.                error("! Bad number of pages option (-n).") ;
  692.             break ;
  693. case 'q' : case 'Q' :
  694.             quiet = 0 ;
  695.             break ;
  696. case 'r' : case 'R' :
  697.             pages[0].reversed = 1;
  698.             break ;
  699. case 'x' :
  700.             if (*p == 0 && argv[i+1])
  701.                p = argv[++i] ;
  702.             while (*p != 0) {
  703.            if (*p == '(' && *(p+1) == '@' ) {
  704.           p+=2; exctransf[excludeseq][0] = myatol(&p); p++;
  705.           }
  706.            else if (*p == '@') {
  707.           p++; exctransf[excludeseq][0] = 1 ;
  708.           }
  709.            exclude[excludeseq][0]=myatol(&p);
  710.                if (*p == '.' && *(p+1) == '.' ) {
  711.                   p += 2;
  712.           if (*p == '(' && *(p+1) == '@' ) {
  713.              p+=2; exctransf[excludeseq][1] = myatol(&p); p++;
  714.              }
  715.           else if (*p == '@') {
  716.              p++; exctransf[excludeseq][1] = 1 ;
  717.              }
  718.           exclude[excludeseq][1] = myatol(&p);
  719.                }
  720.            else {
  721.           exclude[excludeseq][1] = exclude[excludeseq][0];
  722.           exctransf[excludeseq][0] = exctransf[excludeseq][1] ;
  723.           }
  724.            excludeseq++ ;
  725.                if (*p != ',' && *p !=0 )
  726.           error("! Bad page range option (-x).") ;
  727.                if (*p == ',' )
  728.                     p++ ;
  729.             } /* while */
  730.             break ;
  731. case '?' :
  732.             usage() ;
  733.             break ;
  734. default:
  735.         error("! Bad option, not one of filmnqrx?") ;
  736.          }  /* switch c */
  737.       } else {  /* this a file name */
  738.          if (*iname == 0) { /* input file name */
  739.             register char *p ;
  740.  
  741.             lastext = 0 ;
  742.             iname = nextstring ;
  743.             p = argv[i] ;
  744.             while (*p) {
  745.                *nextstring = *p++ ;
  746.                if (*nextstring == '.')
  747.                   lastext = nextstring - iname ;
  748.                else if (*nextstring == '/' || *nextstring == ':')
  749.                   lastext = 0 ;
  750.                nextstring++ ;
  751.             }
  752.             if (lastext == 0) {
  753.                lastext = nextstring - iname ;
  754.                *nextstring++ = '.' ;
  755.                *nextstring++ = 'd' ;
  756.                *nextstring++ = 'v' ;
  757.                *nextstring++ = 'i' ;
  758.             }
  759.             *nextstring++ = 0 ;
  760.             if ((infile=fopen(iname, READBIN))==NULL)
  761.                  error("! can't open input file") ;
  762.  
  763.          } else { /* output file name */
  764.             register char *p ;
  765.  
  766.             lastext = 0 ;
  767.             oname = nextstring ;
  768.             p = argv[i] ;
  769.             while (*p) {
  770.                *nextstring = *p++ ;
  771.                if (*nextstring == '.')
  772.                   lastext = nextstring - oname ;
  773.                else if (*nextstring == '/' || *nextstring == ':')
  774.                   lastext = 0 ;
  775.                nextstring++ ;
  776.             }
  777.             if (lastext == 0) {
  778.                lastext = nextstring - oname ;
  779.                *nextstring++ = '.' ;
  780.                *nextstring++ = 'd' ;
  781.                *nextstring++ = 'v' ;
  782.                *nextstring++ = 'i' ;
  783.             }
  784.             *nextstring++ = 0 ;
  785.            if (freopen(oname, WRITEBIN, stdout)==NULL)
  786.                 error("! can't open output file") ;
  787.          }  /* end output file name */
  788.       } /* else argument with '-' */
  789.    }  /* for */
  790.    if (*iname == 0) {
  791.        (void)fprintf(stderr, banner) ;
  792.        error("! no input file specified");
  793.    }
  794.    if (*oname != 0 && !quiet) {
  795.        (void)fprintf(stderr, banner) ;
  796.        (void)fprintf(stderr, "%s -> %s\n",iname,oname);
  797.        temp = nextstring ;
  798.    }
  799. }
  800. /*
  801.  *   Grabs a pointer, and checks it for validity.
  802.  */
  803. integer ptr(where)
  804. register integer where ;
  805. {
  806.    fseek(infile,where,SEEK_SET);
  807.    where = signedquad() ;
  808.    if (where < -1L || where > inlength)
  809.       error("! dvi file malformed; impossible pointer") ;
  810.    return(where) ;
  811. }
  812.  
  813. /*
  814.  *   This routine store the page locations by tracing the pointers backwards.
  815.  */
  816. void searchpageloc()
  817. {
  818.    integer p,num ;
  819.  
  820.    num=pagecount-1;
  821.    for (p = ptr(postloc+1); num > 0; num--) {
  822.       if (dvibuf(p) != 139)
  823.          error("! missed a bop somehow") ;
  824.       else {
  825.      pageloc[num]=p;
  826.      pagenumbers[num]=signedquad();
  827.      }
  828.       p = ptr(p+41) ;
  829.    }
  830.    pageloc[num]=p;
  831.    (void)dvibuf(p);
  832.    pagenumbers[num]=signedquad();
  833. }
  834. /*
  835.  *   This routine simply reads the entire dvi file, and then initializes
  836.  *   some values about it.
  837.  */
  838. readdvifile() {
  839.    integer p ;
  840.    unsigned char c,d,e ;
  841.  
  842.    fseek(infile, 0L, 2) ;
  843.    inlength = ftell(infile) ;
  844.    if (inlength < 10)
  845.       error("! dvi file too short") ;
  846.    fseek(infile,-3L,SEEK_CUR);
  847.    for (p=inlength - 3; p > 0; p--) {
  848.       c = dvibyte (); d = dvibyte (); e = dvibyte ();
  849.       if (c == 2 && d == 0xdf /* dave fuchs */ &&
  850.                             e == 0xdf)
  851.          break ;
  852.       fseek(infile,-4L,SEEK_CUR);
  853.       }
  854.    if (p < 10)
  855.       error("! rather short dvi file, ain't it?") ;
  856.    postloc = ptr(p-4) ;
  857.    fseek(infile,postloc+5L,SEEK_SET);
  858.    if (signedquad() != 25400000 ||
  859.         signedquad() != 473628672)
  860.       error("! change this program to support non-TeX num/den values") ;
  861.    mag = signedquad() ;
  862.    if (mag < 1 || mag > 1000000)
  863.       error("! impossible magnification value") ;
  864.    fseek(infile,postloc+27L,SEEK_SET);
  865.    pagecount = twobytes() ;
  866.    if (pagecount < 1 || pagecount > 1000000)
  867.       error("! impossible page count value") ;
  868. /*
  869.  *   That's enough error checking; we probably have a correct dvi file.
  870.  *   Let's convert all the values we got from the command line into
  871.  *   units that we can actually use in the dvi file.
  872.  */
  873.    for (p=0; p<pagesperpage; p++) {
  874.       scalemag(&(pages[p].hoffset)) ;
  875.       scalemag(&(pages[p].voffset)) ;
  876.    }
  877. /*
  878.  *   Now let's grab us some font pointers.
  879.  */
  880.    pageloc = (integer *) calloc (pagecount, sizeof (integer));
  881.    if (pageloc == NULL)
  882.       error("!  Not enough memory for allocation of page pointers");
  883.    pagenumbers = (integer *) calloc (pagecount, sizeof (integer));
  884.    if (pagenumbers == NULL)
  885.       error("! Not enough memory for allocation of page numbers array");
  886.    searchpageloc();
  887.    transformpages();
  888.    free(pagenumbers);
  889.    p = postloc + 29 ;
  890.    while (1) {
  891.       c=dvibuf(p);
  892.       if (c == 249)
  893.          break ;
  894.       if (c == 138)
  895.          p++ ;
  896.       else if (c == 243) {
  897.          TeXfonts[dvibyte()] = p ;
  898.          p += fontdeflen(p) ;
  899.       } else
  900.          error("! only nop's and font def's allowed in postamble") ;
  901.    }
  902. /*
  903.  *   Now we check for a landscape special.  It should be the
  904.  *   *first* thing in the page that is at all complicated.
  905.  */
  906.  
  907.    p = pageloc[0L] + 45 ;
  908.    c=dvibuf(p);
  909.    while (comlen[c]) {
  910.       p += comlen[c] ;
  911.       c = dvibuf(p);
  912.    }
  913.    if (c == 239) {
  914.       stringdvibuf(p+2L,9L);
  915.       if (strncmp(temp, "landscape", 9)==0) {
  916.         landscape = p ;
  917.         rem0special = 1 ;
  918.       }
  919.    }
  920. }
  921. /*
  922.  *   Output a single byte, keeping track of where we are.
  923.  */
  924. outdvibyte(c)
  925. unsigned char c ;
  926. {
  927.    fputc(c, stdout) ;
  928.    dviloc++ ;
  929. }
  930. /*
  931.  *   Send out two bytes.
  932.  */
  933. outdvi2(v)
  934. integer v ;
  935. {
  936.    outdvibyte((unsigned char)(v >> 8)) ;
  937.    outdvibyte((unsigned char)(v & 255)) ;
  938. }
  939. /*
  940.  *   Send out a longword.
  941.  */
  942. outdviquad(v)
  943. integer v ;
  944. {
  945.    outdvi2(v >> 16) ;
  946.    outdvi2(v & 65535) ;
  947. }
  948. /*
  949.  *   This routine just copies some stuff from the buffer on out.
  950.  *   Suppose the file is positioned correctly before
  951.  */
  952. putbuf(length)
  953. integer length ;
  954. {
  955.    while ( length-- > 0 )
  956.       outdvibyte(dvibyte()) ;
  957. }
  958. /*
  959.  *   This routine outputs a string, terminated by null.
  960.  */
  961. putstr(s)
  962. register unsigned char *s ;
  963. {
  964.    while (*s)
  965.       outdvibyte(*s++) ;
  966. }
  967. /*
  968.  *   Here we write the preamble to the dvi file.
  969.  */
  970. writepreamble() {
  971. /*   just copy the first 14 bytes of the file */
  972.    fseek(infile,0L,SEEK_SET);
  973.    putbuf(14L) ;
  974. /*   and put our identifier. */
  975.    putstr("\015dvidvi output") ;
  976. }
  977. /*
  978.  *   This routine writes out a font definition.
  979.  */
  980. putfontdef(f)
  981. int f ;
  982. {
  983.    integer p,q ;
  984.  
  985.    p = TeXfonts[f] ;
  986.    q=fontdeflen(p) ;
  987.    fseek(infile,p,SEEK_SET);
  988.    putbuf(q) ;
  989. }
  990. /*
  991.  *   The postamble is next.
  992.  */
  993. writepostamble() {
  994.    int i ;
  995.    integer p ;
  996.  
  997.    p = dviloc ;
  998.    outdvibyte(248) ;
  999.    outdviquad(prevpp) ;
  1000.    fseek(infile,postloc+5,SEEK_SET);
  1001.    putbuf(20L) ;
  1002.    outdvi2(twobytes()+1L) ; /* increase stack depth by 1 */
  1003.    outdvi2(outputpages) ;
  1004.    for (i=0; i<256; i++)
  1005.       if (fontseen[i])
  1006.          putfontdef(i) ;
  1007.    outdvibyte(249) ;
  1008.    outdviquad(p) ;
  1009.    outdvibyte(2) ;
  1010.    outdviquad(0xdfdfdfdfL) ;
  1011.    while (dviloc & 3)
  1012.       outdvibyte(0xdf) ;
  1013.    fclose(stdout) ;
  1014. }
  1015. /*
  1016.  *   This routine starts a page, by writing out a bop command.
  1017.  */
  1018. beginpage() {
  1019.    int i ;
  1020.    integer p ;
  1021.  
  1022.    p = dviloc ;
  1023.    outdvibyte(139) ;
  1024.    outdviquad(outputpages+1) ;
  1025.    for (i=0; i<9; i++)
  1026.       outdviquad(0L) ;
  1027.    outdviquad(prevpp) ;
  1028.    prevpp = p ;
  1029. }
  1030. /*
  1031.  *   This routine sends out a page.  We need to handle the
  1032.  *   landscape special, though.
  1033.  */
  1034. dopage(num)
  1035. integer num ;
  1036. {
  1037.    register integer p,q ;
  1038.    register int len ;
  1039.    integer v, oldp ;
  1040.    unsigned char c;
  1041.  
  1042. /*
  1043.  *   We want to take the base 10 log of the number.  It's probably
  1044.  *   small, so we do it quick.
  1045.  */
  1046.    if (! quiet) {
  1047.       int t = num+1, i = 0 ;
  1048.       if (t < 0) {
  1049.          t = -t ;
  1050.          i++ ;
  1051.       }
  1052.       do {
  1053.          i++ ;
  1054.          t /= 10 ;
  1055.       } while (t > 0) ;
  1056.       if (i + prettycolumn > 76) {
  1057.          fprintf(stderr, "\n") ;
  1058.          prettycolumn = 0 ;
  1059.       }
  1060.       prettycolumn += i + 1 ;
  1061. #ifdef SHORTINT
  1062.       (void)fprintf(stderr, "[%ld", num+1) ;
  1063. #else  /* ~SHORTINT */
  1064.       (void)fprintf(stderr, "[%d", num+1) ;
  1065. #endif /* ~SHORTINT */
  1066.       (void)fflush(stderr) ;
  1067.    }
  1068.    p = pageloc[num] + 45 ;
  1069.    c=dvibuf(p);
  1070.    while (c != 140) {
  1071.       if ((len=comlen[c]) > 0) {    /* most commands are simple */
  1072.          outdvibyte(c);
  1073.          putbuf((long)len-1) ;
  1074.          p += len ;
  1075.       } else {   /* but there are a few we need to treat specially */
  1076.          len = c ;
  1077.          if (171 <= len && len <= 235) {
  1078.             p++ ;
  1079.             if (len == 235)
  1080.                { len = dvibyte (); p++ ;}
  1081.             else
  1082.                len -= 171 ;
  1083.             if (!fontseen[len]) {
  1084.                putfontdef(len) ;
  1085.                fontseen[len] = 1 ;
  1086.                fseek(infile,p,SEEK_SET);
  1087.             }
  1088.             if (len < 64)
  1089.                outdvibyte(171 + len) ;
  1090.             else {
  1091.                outdvibyte(235) ;
  1092.                outdvibyte(len) ;
  1093.             }
  1094.          } else {
  1095.             v = 0 ;
  1096.             oldp = p++ ;
  1097.             switch(len) {
  1098. case 242:      v = dvibyte() ; p++ ;  break ;
  1099. case 241:      v = (v << 8) + dvibyte() ; p++ ; break ;
  1100. case 240:      v = (v << 8) + dvibyte() ; p++ ; break ;
  1101. case 239:      v = (v << 8) + dvibyte() ; p++ ;
  1102. /*
  1103.  *   Remove a landscape special on page 0, if one is found.
  1104.  */            stringdvibuf(oldp + len - 327,9);
  1105.                if (num || ! rem0special ||
  1106.                     strncmp(temp, "landscape", 9)) {
  1107.                   fseek (infile,oldp,SEEK_SET);
  1108.                   putbuf(v + len - 237) ;
  1109.                   }
  1110.                p = oldp + v + len - 237 ;
  1111.                fseek(infile,p,SEEK_SET);
  1112.                break ;
  1113. case 243: case 244: case 245: case 246:
  1114.                p += len - 230 ;
  1115.                p += dvibuf(p) ;
  1116.                p += dvibyte() + 2 ;
  1117.                fseek(infile,p,SEEK_SET);
  1118.                break ;
  1119. default:       fprintf(stderr, "Bad dvi command was %d at %ld\n", len, p) ;
  1120.                error("! lost sync dvi in file lost dvi sync file in") ;
  1121.             }
  1122.          }
  1123.       }
  1124.       c=dvibyte();
  1125.    }
  1126.    if (! quiet) {
  1127.       (void)fprintf(stderr, "] ") ;
  1128.       (void)fflush(stderr) ;
  1129.       prettycolumn += 2 ;
  1130.    }
  1131. }
  1132. /*
  1133.  *   Here we end a page.  Simple enough.
  1134.  */
  1135. endpage() {
  1136.    outputpages++ ;
  1137.    outdvibyte(140) ;
  1138. }
  1139. /*
  1140.  *   This is our main routine for output, which runs through all the
  1141.  *   pages we need to output.
  1142.  */
  1143. writedvifile() {
  1144.    integer pagenum ;
  1145.    int ppp ;
  1146.    integer actualpageno ;
  1147.    struct pagespec *ps ;
  1148.    integer p ;
  1149.    Boolean beginp ;
  1150.  
  1151.    writepreamble() ;
  1152.    pagefake = (pagecount + modulo - 1) / modulo * modulo ;
  1153.    if ( maxpages < pagefake ) pagefake = maxpages;
  1154.    for (pagenum = 0; pagenum < pagefake; pagenum += modulo) {
  1155.       beginp = 1 ;
  1156.       for (ppp = 0, ps=pages; ppp < pagesperpage; ppp++, ps++) {
  1157.          if (ps->reversed)
  1158.             actualpageno = pagefake - pagenum - modulo + ps->pageno ;
  1159.          else
  1160.             actualpageno = pagenum + ps->pageno ;
  1161.          if (actualpageno < pagecount && selectedpage(actualpageno+1) ) {
  1162.             if (beginp) {
  1163.                 beginpage() ;
  1164.                 beginp = 0 ;
  1165.             }
  1166.             if (landscape) {
  1167.                 fseek(infile,landscape,SEEK_SET);
  1168.                 putbuf(dvibuf(landscape+1)+2L) ;
  1169.                 landscape = 0 ;
  1170.             }
  1171.             if (pagesperpage)
  1172.                 outdvibyte(141) ;
  1173.             if (ps->hoffset) {
  1174.                 outdvibyte(146) ;
  1175.                 outdviquad(ps->hoffset) ;
  1176.             }
  1177.             if (ps->voffset) {
  1178.                 outdvibyte(160) ;
  1179.                 outdviquad(ps->voffset) ;
  1180.             }
  1181.             dopage(actualpageno) ;
  1182.             if (pagesperpage)
  1183.                 outdvibyte(142) ;
  1184.          }
  1185.       }
  1186.       if (beginp != 1) endpage() ;
  1187.    }
  1188.    writepostamble() ;
  1189. }
  1190. main(argc, argv)
  1191. int argc ;
  1192. char *argv[] ;
  1193. {
  1194.    processargs(argc, argv) ;
  1195.    readdvifile() ;
  1196.    writedvifile() ;
  1197. }
  1198.  
  1199.